package com.xlx.openLink.snmp.utils;

import com.xlx.openLink.base.SnmpException;
import com.xlx.openLink.entity.baseenity.OMMappingInfo;
import com.xlx.openLink.entity.pojo.Device;
import com.xlx.openLink.snmp.SNMPSysConfig;
import com.xlx.openLink.snmp.base.SNMPTarget;
import com.xlx.openLink.snmp.snmpenum.VersionEnum;
import com.xlx.openLink.uitls.DefaultConstant;
import jdk.nashorn.internal.runtime.regexp.joni.Regex;
import lombok.extern.slf4j.Slf4j;
import net.percederberg.mibble.MibType;
import net.percederberg.mibble.MibValueSymbol;
import net.percederberg.mibble.snmp.SnmpIndex;
import net.percederberg.mibble.snmp.SnmpObjectType;
import net.percederberg.mibble.value.ObjectIdentifierValue;
import org.apache.commons.lang3.StringUtils;
import org.snmp4j.*;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.*;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * @author seven
 * @create 2019-06-09 16:18
 **/
@Slf4j
public class SNMPUtils {

    private static String community = "public";
    private static String ipAddress = "udp:10.0.0.106/";
    public static final String DEFAULT_PROTOCOL = "udp";
    public static Integer version = 1;
    public static Integer port = 161;

    /**
     * 校验请求是否错误
     *
     * @param responseEvent
     * @throws SnmpException
     */
    public static void checkSNMPErro(ResponseEvent responseEvent) throws SnmpException {
        if (responseEvent.getError() != null) {
            throw new SnmpException(responseEvent.getError(), "返回错误");
        } else {
            PDU pdu = responseEvent.getResponse();
            if (pdu == null) {
                throw new SnmpException("time out");
            } else if (pdu.getErrorStatus() != 0) {
                if (pdu.getErrorStatus() == 2) {
                    throw new SnmpException("no find oid");
                } else {
                    throw new SnmpException(pdu.getErrorStatusText());
                }
            } else {
                VariableBinding variableBinding = pdu.get(0);
                if (variableBinding == null) {
                    throw new SnmpException("time out");
                } else {
                    Vector vector = pdu.getVariableBindings();
                    if (vector.size() <= 0) {
                        throw new SnmpException("time out");
                    }
                }
            }
        }
    }

    public static String getMibOIDofClass(Class clazz) throws Exception {
        try {
            Object obj = clazz.newInstance();
            return ((OMMappingInfo) obj).getMappingOID();
        } catch (Exception exception) {
            throw new Exception("类文件加载错误");
        }
    }


    public static Vector getFieldsInMibNode(Class clazz, MibValueSymbol mibValueSymbol) {
        Field[] fields = clazz.getDeclaredFields();
        Vector var3 = new Vector();
        for (int i = 0; i < fields.length; ++i) {
            String name = fields[i].getName();
            MibValueSymbol[] mibValueSymbols = mibValueSymbol.getChildren();
            for (int j = 0; j < mibValueSymbols.length; ++j) {
                if (mibValueSymbols[j].getName().equals(name)) {
                    var3.add(mibValueSymbols[j]);
                    break;
                }
            }
        }

        return var3;
    }

    /**
     * 获取对象相关节点
     *
     * @param clazz
     * @param mibValueSymbol
     * @return
     */
    public static List getFieldsInMibNodeNew(Class clazz, MibValueSymbol mibValueSymbol) {
        Field[] fields = clazz.getDeclaredFields();
        List list = new ArrayList();
        for (int i = 0; i < fields.length; ++i) {
            String name = fields[i].getName();
            MibValueSymbol[] mibValueSymbols = mibValueSymbol.getChildren();
            for (int j = 0; j < mibValueSymbols.length; j++) {
                if (mibValueSymbols[j].getName().equals(name)) {
                    list.add(mibValueSymbols[j]);
                    break;
                }
            }
        }
        return list;
    }

    /**
     * 根据查询出来的方法设置值到对象中去
     *
     * @param obj
     * @param str
     * @param var
     */
    public static void setFieldValue(Object obj, String str, Variable var) {
        try {
            String methodName = "set" + str.replaceFirst(str.substring(0, 1), str.substring(0, 1).toUpperCase());
            Class clazz = obj.getClass();
            Field field = clazz.getDeclaredField(str);
            if (field == null) {
                return;
            }
            Class fieldType = field.getType();
            Method method = clazz.getMethod(methodName, fieldType);
            String typeName = fieldType.getName();
            if (typeName.equalsIgnoreCase("int")) {
                int value = var.toInt();
                if (var instanceof Null) {
                    value = 0;
                }

                method.invoke(obj, new Integer(value));
            } else if (typeName.equalsIgnoreCase("long")) {
                long value = var.toLong();
                if (var instanceof Null) {
                    value = 0L;
                }
                method.invoke(obj, new Long(value));
            } else if (typeName.equalsIgnoreCase("java.lang.String")) {
                method.invoke(obj, var.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static boolean canPing(String var0) {
        try {
            InetAddress var1 = InetAddress.getByName(var0);
            return var1.isReachable(2000);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static String formatDispayMacAddress(String var0) {
        if (var0 != null && !var0.equals("") && !var0.equalsIgnoreCase("null")) {
            try {
                OctetString var1 = new OctetString(var0.getBytes("utf-8"));
                return var1.toHexString();
            } catch (Exception var2) {
                var2.printStackTrace();
                return "";
            }
        } else {
            return "";
        }
    }

    /**
     * 判断是组还是表格
     *
     * @param obj
     * @param mibValueSymbol
     * @return
     * @throws SnmpException
     */
    public static String getTableOrGroupIndexOID(Object obj, MibValueSymbol mibValueSymbol) throws SnmpException {
        if (!mibValueSymbol.isTableRow()) {
            return "0";
        } else {
            String index;
            if (obj instanceof OMMappingInfo) {
                index = ((OMMappingInfo) obj).getTableIndexOID();
                if (index != null && !index.equals("")) {
                    return index;
                }
            }
            index = "";
            ArrayList arrayList = ((SnmpObjectType) mibValueSymbol.getType()).getIndex();
            for (int i = 0; i < arrayList.size(); i++) {
                SnmpIndex var5 = (SnmpIndex) arrayList.get(i);
                ObjectIdentifierValue var6 = (ObjectIdentifierValue) var5.getValue();
                String var7 = var6.getName();
                    index = index + getFieldValue(obj, var7, ((SnmpObjectType) var6.getSymbol().getType()).getSyntax());
            }
            return index;
        }
    }

    public static String getTableIndexOID(Object obj, MibValueSymbol mibValueSymbol) throws SnmpException {
        String index = null;
        if (mibValueSymbol.isTableRow()) {
            if (obj instanceof OMMappingInfo) {
                index = ((OMMappingInfo) obj).getTableIndexOID();
                if (StringUtils.isNoneEmpty(index)) {
                    return index;
                }
            }
            index = "";
            ArrayList arrayList = ((SnmpObjectType) mibValueSymbol.getType()).getIndex();
            for (int i = 0; i < arrayList.size(); ++i) {
                SnmpIndex var5 = (SnmpIndex) arrayList.get(i);
                ObjectIdentifierValue var6 = (ObjectIdentifierValue) var5.getValue();
                String var7 = var6.getName();
                index = index + getFieldValue(obj, var7, ((SnmpObjectType) var6.getSymbol().getType()).getSyntax());
            }
            return index;
        } else {


        }

        if (!mibValueSymbol.isTableRow()) {
            return "0";
        } else {

        }
        return null;
    }


    public static Variable getFieldValue(Object var0, String var1, MibType var2) {
        try {
            String var3 = "get" + var1.replaceFirst(var1.substring(0, 1), var1.substring(0, 1).toUpperCase());
            Class var4 = var0.getClass();
            Field var5 = var4.getDeclaredField(var1);
            if (var5 == null) {
                return null;
            } else {
                Method var6 = var4.getMethod(var3);
                Object var7 = var6.invoke(var0);
                return getVariable(var2, var7);
            }
        } catch (Exception var8) {
            // MyLog.err(Messages.getString("SNMPUtils.10") + var0.getClass() + Messages.getString("SNMPUtils.11") + var1 + Messages
            // .getString("SNMPUtils.12") + var8.getMessage());
            //MyLog.debug(var8);
            return new Null();
        }
    }

    public static Variable getVariable(MibType var0, Object var1) {
        if (var0.hasTag(0, 2)) {
            Integer32 var12 = new Integer32();
            var12.setValue("" + var1);
            return var12;
        } else if (var0.hasTag(1, 1)) {
            Counter32 var11 = new Counter32();
            var11.setValue("" + var1);
            return var11;
        } else if (var0.hasTag(1, 2)) {
            Gauge32 var10 = new Gauge32();
            var10.setValue("" + var1);
            return var10;
        } else if (var0.hasTag(0, 4)) {
            OctetString var9 = new OctetString();

            try {
                byte[] var3 = ("" + var1).getBytes("utf-8");
                var9 = new OctetString(var3);
            } catch (Exception var4) {
                ;
            }

            return var9;
        } else if (var0.hasTag(0, 6)) {
            OID var8 = new OID("" + var1);
            return var8;
        } else if (var0.hasTag(1, 0)) {
            IpAddress var7 = new IpAddress("" + var1);
            return var7;
        } else if (var0.hasTag(1, 3)) {
            TimeTicks var6 = new TimeTicks();
            var6.setValue("" + var1);
            return var6;
        } else if (var0.hasTag(1, 4)) {
            Opaque var5 = new Opaque(("" + var1).getBytes());
            return var5;
        } else if (var0.hasTag(1, 6)) {
            Counter64 var2 = new Counter64();
            var2.setValue("" + var1);
            return var2;
        } else {
            //MyLog.err(Messages.getString("SNMPUtils.23") + var0);
            return new Null();
        }
    }

    public static Snmp initSnmp(SNMPTarget target) throws IOException {
        Snmp snmp = null;
        //1、初始化多线程消息转发类
        MessageDispatcher messageDispatcher = new MessageDispatcherImpl();
        //其中要增加三种处理模型。如果snmp初始化使用的是Snmp(TransportMapping<? extends Address> transportMapping) ,就不需要增加
        messageDispatcher.addMessageProcessingModel(new MPv1());
        messageDispatcher.addMessageProcessingModel(new MPv2c());
        //当要支持snmpV3版本时，需要配置user
        if (target.getSnmpVersion() == SnmpConstants.version3) {
            USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
            UsmUser user = new UsmUser(new OctetString("SNMPV3"), AuthSHA.ID, new OctetString("authPassword"), PrivAES128.ID,
                    new OctetString("privPassword"));
            usm.addUser(user.getSecurityName(), user);
            messageDispatcher.addMessageProcessingModel(new MPv3(usm));
        }
        TransportMapping transportMapping = new DefaultUdpTransportMapping();
        //3、正式创建snmp
        snmp = new Snmp(messageDispatcher, transportMapping);
        //开启监听
        snmp.listen();
        return snmp;
    }

    //2.创建目标地址对象
    public static Target createTarget(SNMPTarget snmpTarget, int targetType) {
        if (VersionEnum.getByVersion(snmpTarget.getSnmpVersion()) == null) {
            log.error("版本号错误");
            return null;
        }
        Address address = GenericAddress.parse(DEFAULT_PROTOCOL + ":" + snmpTarget.getNodeIP() + "/" + snmpTarget.getPort());
        if (snmpTarget.getSnmpVersion() == VersionEnum.version3.getVersion()) {
            UserTarget target = new UserTarget();
            //IP+Port
            target.setAddress(address);
            //VersionEnum
            target.setVersion(snmpTarget.getSnmpVersion());
            //timeout
            target.setTimeout(snmpTarget.getTargetSnmpTimeout());
            //Retries
            target.setRetries(snmpTarget.getTargetSnmpRetry());
            target.setSecurityLevel(snmpTarget.getV3SecurityLevel());
            target.setSecurityName(new OctetString(snmpTarget.getV3User()));
            target.setSecurityModel(snmpTarget.getV3SecurityLevel());
            return target;
        } else {
            CommunityTarget target = new CommunityTarget();
            //IP+Port
            target.setAddress(address);
            //VersionEnum
            target.setVersion(snmpTarget.getSnmpVersion());
            //Community
            //targetType  1:SET  0：GET
            if (targetType == DefaultConstant.SNMP_COMMUNITY_SET) {

                target.setCommunity(new OctetString(snmpTarget.getWriteCommunity()));
            } else {
                target.setCommunity(new OctetString(snmpTarget.getReadCommunity()));
            }
            //timeout
            target.setTimeout(SNMPSysConfig.getSnmpTimeout());
            //Retries
            target.setRetries(SNMPSysConfig.getSnmpRetry());
            return target;
        }
    }

    /**
     * 构造
     *
     * @param device
     * @return
     */
    public static SNMPTarget getSNMPTarget(Device device) {
        SNMPTarget snmpTarget = new SNMPTarget();
        snmpTarget.setReadCommunity(device.getDevReadcommunity() == null ? community : device.getDevReadcommunity());
        snmpTarget.setSnmpVersion(device.getDevSnmpVersion() == null ? version : device.getDevSnmpVersion());
        snmpTarget.setPort(device.getDevSnmpPort() == null ? port : device.getDevSnmpPort());
        return snmpTarget;
    }

    public static String convertHexToString(String hex) {

        StringBuilder sb = new StringBuilder();
        StringBuilder temp = new StringBuilder();

        for (int i = 0; i < hex.length() - 1; i += 2) {

            //grab the hex in pairs
            String output = hex.substring(i, (i + 2));
            //convert hex to decimal
            int decimal = Integer.parseInt(output, 16);
            //convert the decimal to character
            sb.append((char) decimal);

            temp.append(decimal);
        }

        return sb.toString();
    }

    /**
     * 关闭snmp连接的最终方法
     *
     * @param snmp
     */
    public static void closeSnmp(Snmp snmp) {
        if (snmp != null) {
            try {
                snmp.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static Vector getWritedFieldsInMibNode(Class var0, MibValueSymbol var1) {
        Field[] var2 = var0.getDeclaredFields();
        Vector var3 = new Vector();

        for (int var4 = 0; var4 < var2.length; ++var4) {
            String var5 = var2[var4].getName();
            MibValueSymbol[] var6 = var1.getChildren();

            for (int var7 = 0; var7 < var6.length; ++var7) {
                if (var6[var7].getName().equals(var5)) {
                    SnmpObjectType var8 = (SnmpObjectType) var6[var7].getType();
                    if (var8.getAccess().canWrite()) {
                        var3.add(var6[var7]);
                        break;
                    }
                }
            }
        }

        return var3;
    }

}
